package com.whz.gateway.common.util;

import com.whz.gateway.common.constants.GatewayConstant;
import com.whz.gateway.user.UserDetailInfo;
import com.whz.generic.utils.UrlCodecUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;

import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @author whz
 */
@Slf4j
@UtilityClass
public class HeaderUtils {

    public static final String BEARER = "Bearer";
    public static final String API_BEARER = "Api-Bearer";
    public static final String ACCESS_TOKEN_VALUE = HeaderUtils.class.getName() + "_ACCESS_TOKEN_VALUE";
    public static final String CURRENT_USER_PERMISSIONS = HeaderUtils.class.getName() + "_CURRENT_USER_PERMISSIONS";

    /**
     * 添加不存在的header
     */
    public static ServerWebExchange addIfAbsent(final ServerWebExchange exchange, final Map<String, String> header) {
        return exchange.mutate().request(exchange.getRequest().mutate().headers(h -> header.forEach((name, value) -> {
                    if (StringUtils.hasText(value)) {
                        /*
                         * http header 不支持中文 见 https://blog.robotshell.org/2012/deal-with-http-header-encoding-for-file-download/
                         */
                        h.addIfAbsent(name, UrlCodecUtils.urlEncode(value));
                    }
                })
        ).build()).build();
    }


    /**
     * 获取当前登录token
     *
     * @param request 当前请求
     * @return token or null
     */
    public static TokenInfo currentToken(final ServerHttpRequest request) {
        List<String> headers = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
        if (CollectionUtils.isEmpty(headers)) {
            if (log.isDebugEnabled()) {
                log.debug("cannot found authorization header.");
            }
            // 查cookie 无bearer
            HttpCookie token = request.getCookies().getFirst(HttpHeaders.AUTHORIZATION);
            if (token != null) {
                return new TokenInfo(token.getValue(), TokenBiz.USER);
            }
            // 查query参数 无bearer
            String va = request.getQueryParams().getFirst(HttpHeaders.AUTHORIZATION);
            return new TokenInfo(va, TokenBiz.USER);
        }
        for (String value : headers) {
            log.info("find authorization :{} from header", value);
            if (value.toLowerCase().startsWith(BEARER.toLowerCase())) {
                return new TokenInfo(computeToken(value.substring(BEARER.length()).trim()), TokenBiz.USER);
            } else if (value.toLowerCase().startsWith(API_BEARER.toLowerCase())) {
                return new TokenInfo(computeToken(value.substring(API_BEARER.length()).trim()), TokenBiz.API);
            } else {
                // 不是bearer类型的,空格分开的
                String[] split = StringUtils.split(value, " ");
                if (split != null && split.length > 1) {
                    return new TokenInfo(split[1], TokenBiz.USER);
                }
            }
        }
        return null;
    }

    public static String currentClient(ServerWebExchange exchange) {
        // TODO 从currentUserDetails(exchange) 查询用户的ClientId
        return null;
    }

    @Data
    @AllArgsConstructor
    public static class TokenInfo {
        private String token;
        private TokenBiz biz;
    }

    public enum TokenBiz {
        /**
         * access token 来源 API: Api-Bearer access_token
         */
        API,
        /**
         * access token 来源用户 Bearer access_token
         */
        USER
    }

    private static String computeToken(String value) {
        String authHeaderValue = value;
        int commaIndex = authHeaderValue.indexOf(',');
        if (commaIndex > 0) {
            authHeaderValue = authHeaderValue.substring(0, commaIndex);
        }
        return authHeaderValue;
    }

    public static void saveAttribute(final ServerWebExchange exchange, String key, Object value) {
        exchange.getAttributes().putIfAbsent(key, value);
    }

    public static void saveTokenValue(final ServerWebExchange exchange, TokenInfo token) {
        saveAttribute(exchange, ACCESS_TOKEN_VALUE, token);
    }

    public static void saveCurrentUserDetails(final ServerWebExchange exchange, UserDetailInfo userDetails) {
        saveAttribute(exchange, GatewayConstant.USER_DETAILS_ATTRIBUTE, userDetails);
    }

    public static UserDetailInfo currentUserDetails(final ServerWebExchange exchange) {
        return (UserDetailInfo) exchange.getAttributes().get(GatewayConstant.USER_DETAILS_ATTRIBUTE);
    }

    public static HeaderUtils.TokenInfo getTokenValue(final ServerWebExchange exchange) {
        return (HeaderUtils.TokenInfo) exchange.getAttributes().getOrDefault(ACCESS_TOKEN_VALUE, null);
    }

    public static <T> void savePermissions(final ServerWebExchange exchange,
                                           final Collection<T> permissions) {
        saveAttribute(exchange, CURRENT_USER_PERMISSIONS, permissions);
    }

    /**
     * 查询当前登录token的权限列表
     *
     * @param exchange exchange
     * @return 当前权限列表
     */
    @SuppressWarnings("unchecked")
    public static <T> Collection<T> currentPermissions(final ServerWebExchange exchange) {
        return (Collection<T>) exchange.getAttributes().get(CURRENT_USER_PERMISSIONS);
    }
}